/*
 *  Chaos Cube Main Program: Andrew Milian, Team Mattt 
 *    ECEN 4013: Senior Design 1
 *
 *    Includes: IR.h
 *              audio.h
 *              visual.h
 *              IMU.h
 *              ChaosCube.h
 */


#include <msp430g2553.h>
#include "ChaosCube.h"


//#define DEBUG


char int_flag;           // Interrupt flag to restrict program flow
int face_value = failure;
int timeout_count = 0;
int VISUAL_RELEASE = 0;

void main(void)
{
  initClocks();

  while(1){
    initPorts();

    //////////////////////////
    /* Start Charging Phase */
    //////////////////////////

    initGen();                            // Initialize for generation phase
    __delay_cycles( delay_us * 100 );

    _BIS_SR( LPM0_bits + GIE );           // Enter Low Power Mode (Wait for Generator interrupt)

     /** Waiting_Gen_Interrupt **/
     while( !(int_flag & F_GEN) );

    /* Indicate Charged */
    initAudio();
    initVisual();

    sendAudio( success );
    sendVisual( success );


    /////////////////////////
    /* Start Rolling Phase */
    /////////////////////////

    initIMU();
    initIR();

    face_value = waitRoll();

    // Reset timeout
    TA0CTL |= TACLR;
    timeout_count = 0;


    /* Transmit for face_value if F_TIMEOUT not set */
    if( face_value && !(int_flag & F_TIMEOUT) ){

	  /* Rolled_Transmit_Outputs */
      sendAudio( face_value );
      sendIR( face_value );
      sendVisual( face_value );
    }

    /* If face_value return: FAILURE */
    if( !face_value ){
      sendAudio( failure );
      sendVisual( failure );
    }

  } // End while(1)

} // End of main






/////////////////////////////
/* Initialization Routines */
/////////////////////////////


// Configure internal oscillators and watchdog timer
void initClocks(void)
{
  WDTCTL = WDTPW + WDTHOLD;	             // disable watchdog

  BCSCTL1 =CALBC1_8MHZ;                  //set range
  DCOCTL = CALDCO_8MHZ;	                 //set DCO step+ modulation
  BCSCTL3 |= LFXT1S_2;	                 //LFXT1 = VLO
  IFG1 &= ~OFIFG;                        //clear OSCFault flag
  BCSCTL2 |= SELM_0 +DIVM_0 +DIVS_0;	 //MCLK = DCO, SMCLK = DCO

} // end of initClocks


// Initialize timer A0 to measure 0.05s time periods
void initTimeOut(void)
{
  // Time out, 5s/100 = cycles/ (8 MHz / 8)
  TA0CCR0 = 50000;
  // Enable interrupts for CCR0.
  TA0CCTL0 = CCIE;
  // SMCLK, div 8, up mode, clear timer
  TA0CTL = TASSEL_2 + ID_3 + MC_1 + TACLR;

} // End of initTimeOut 


// Initialize the ADC to interpret voltage on the SuperCap
void initGen(void)
{

  // Disable ADC Conversions to update registers
  ADC10CTL0 &= ~ENC;
  // Use 1/2Vcc & Vss for Up & Low Refs, 16 x ADC10CLKs, turn on ADC
  ADC10CTL0 = SREF_0  + ADC10ON + REF2_5V + REFON + ADC10IE;
  // A0 input, use ADC10CLK div 1, single channel mode  + ADC10DIV_0
  ADC10CTL1 =  ADC10SSEL_1 + ADC10SSEL_0;
  // Enable ADC input on P1.0 / A0
  ADC10AE0 = BIT0;
  // Enable conversions.
  ADC10CTL0 |= ENC + ADC10SC;

} // End of initGen

// Initalize ports to inputs except hold VISUAL_BLANK high
void initPorts(void)
{

  P1OUT &= ~0xFF;
  P2OUT &= ~0xFF;
  P2OUT |= P_VISUAL_BLANK;
  P2DIR |= P_VISUAL_BLANK;
  P3OUT &= ~0xFF;

}

/////////////////////
/* Other Functions */
/////////////////////

// Waits for a number of milliseconds (Approximate! not exact)
void delay_ms(unsigned int num_ms)
{
  int k = num_ms;
  while(k != 0){
    __delay_cycles(1000 * delay_us);
    k -= 1;
  }
}


////////////////////////////////
/* Interrupt Service Routines */
////////////////////////////////


#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void) {

  int adcval = ADC10MEM;

  // 4.7 V on ADC input
  if ( adcval >= 480 ) {
    // Set GenerationPhaseFlag
    int_flag |= F_GEN;
	// Disable ADC interrupts
    ADC10CTL0 &= ADC10IE;
    // Shut off ADC
    ADC10CTL0 &= ADC10ON;
    // Return to main program out of LPM0
    LPM0_EXIT;
	}

	else{
	  //Start next conversion
	  ADC10CTL0 |= ENC + ADC10SC;
	}
} // ADC10_ISR


#pragma vector = TIMER0_A0_VECTOR
__interrupt void TA0_CCR0_ISR(void) {

  if( timeout_count >= 100 ){
    int_flag |= F_TIMEOUT;                   // Set TimeOutFlag
    timeout_count = 0;
    VISUAL_RELEASE = 1;

    /* If face_value has not returned: Roll has timed out, display failure and enter LPM */
    if( !face_value ){
      /** Timed_Out_Send_Audio **/
      sendAudio(failure);
      /** Timed_Out_Send_Visual **/
      sendVisual(failure);

      SVSCTL |= PORON;
    }

    P2OUT |= P_VISUAL_BLANK;

    #ifdef DEBUG
      /** Time_Out_Interrupt **/
      P1OUT |= BIT3;
      P1DIR |= BIT3;
    #endif
  }

  timeout_count = timeout_count + 1;

} // TA0_CCR0_ISR
